#include "SmileStore.h"
#include "SmileStruct.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <mpich2/mpi.h>

#include <vector>
#include <algorithm>
#include <functional>
#include <fstream>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTH_LINGO 4
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
smileStore::smileStore():filename(NULL), allSmiles(NULL), numberSmiles(0), lingoSimilarity(NULL), averageSimDistance(NULL) {}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
smileStore::smileStore(char *filename_tmp):allSmiles(NULL), numberSmiles(0), lingoSimilarity(NULL), averageSimDistance(NULL) {

  filename = new char[strlen(filename_tmp) + 1];
  strcpy(filename, filename_tmp);

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
smileStore::~smileStore() {

  if (filename)   delete[] filename;
  if (allSmiles)  delete[] allSmiles;

  if (lingoSimilarity) {
    for (int i = 0; i < numberSmiles; i++) if (lingoSimilarity[i]) delete[] lingoSimilarity[i];
    delete[] lingoSimilarity;
  }

  if (averageSimDistance) delete[] averageSimDistance;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::Filename(char *filename_tmp) {

  if (filename) delete[] filename;
  filename = new char[strlen(filename_tmp) + 1];
  strcpy(filename, filename_tmp);

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::AllSmiles(const smileStruct *allSmiles_tmp, int numberSmiles_tmp) {

  if (allSmiles) delete[] allSmiles;
  numberSmiles  = numberSmiles_tmp;
  allSmiles     = new smileStruct[numberSmiles_tmp];
  for (int i = 0; i < numberSmiles_tmp; i++)
    allSmiles[i] = allSmiles_tmp[i];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::NumberSmiles(int numberSmiles_tmp) {

  numberSmiles = numberSmiles_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::LingoSimililarity(double **lingoSimilarity_tmp, int numberSmiles_tmp) {

  if (lingoSimilarity) {
    for (int i = 0; i < numberSmiles; i++) if (lingoSimilarity[i]) delete[] lingoSimilarity[i];
    delete[] lingoSimilarity;
  }

  lingoSimilarity = new double*[numberSmiles_tmp];
  for (int i = 0; i < numberSmiles_tmp; i++) lingoSimilarity[i] = new double[numberSmiles_tmp];

  for (int i = 0; i < numberSmiles_tmp; i++)
    for (int j = 0; j < numberSmiles_tmp; j++)
      lingoSimilarity[i][j] = lingoSimilarity_tmp[i][j];

  numberSmiles = numberSmiles_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::AverageSimDistance(double *averageSimDistance_tmp, int numberSmiles_tmp) {

  if (averageSimDistance) delete[] averageSimDistance;

  averageSimDistance = new double[numberSmiles_tmp];
  for (int i = 0; i < numberSmiles_tmp; i++)
          averageSimDistance[i] = averageSimDistance_tmp[i];

  numberSmiles = numberSmiles_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
char* smileStore::Filename(void) {

  return filename;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::AllSmiles(smileStruct *allSmiles_tmp) {

  if (allSmiles_tmp) delete[] allSmiles_tmp;
  allSmiles_tmp = new smileStruct[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) allSmiles_tmp[i] = allSmiles[i];
  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::NumberSmiles(void) {

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::LingoSimililarity(double **lingoSimilarity_tmp) {

    if (lingoSimilarity_tmp) {
            for (int i = 0; i < numberSmiles; i++) if (lingoSimilarity_tmp[i]) delete[] lingoSimilarity_tmp[i];
            delete[] lingoSimilarity_tmp;
    }

    lingoSimilarity_tmp = new double*[numberSmiles];
    for (int i = 0; i < numberSmiles; i++) lingoSimilarity_tmp[i] = new double[numberSmiles];

    for (int i = 0; i < numberSmiles; i++)
            for (int j = 0; j < numberSmiles; j++)
                    lingoSimilarity_tmp[i][j] = lingoSimilarity[i][j];

    return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::AverageSimDistance(double *averageSimDistance_tmp) {

  if (averageSimDistance_tmp) delete[] averageSimDistance_tmp;

  averageSimDistance_tmp = new double[numberSmiles];
  for (int i = 0; i < numberSmiles; i++)
          averageSimDistance_tmp[i] = averageSimDistance[i];

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
smileStruct* smileStore::OneSmileStruct(int position) {

  //printf("Number %d %d %s\n", numberSmiles, position, allSmiles[50000].Code());
  if (!numberSmiles || !allSmiles) ExtractSmiles();
  if (position > numberSmiles) return NULL;
  return &allSmiles[position];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
double smileStore::OneAverageSimDistance(int position) {

  if (position > numberSmiles) return 0.0;
  return averageSimDistance[position];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ExtractSmiles(void) {

  if (!filename) return 0;

  ifstream  filestr;

  filestr.open (filename, ios::in);
  if (!filestr.is_open()) return 0;

  char    *lineInput = new char[1000];
  int      numberLine = 0;

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) numberLine++;
  }

  numberSmiles = numberLine;
  if (allSmiles) delete[] allSmiles;
  allSmiles = new smileStruct[numberSmiles];
  numberLine = 0;

  filestr.close();
  filestr.open (filename, ios::in);

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) allSmiles[numberLine++].InputLine(lineInput);
  }
  filestr.close();

  delete[] lineInput;

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ExtractSmiles(char *filename_tmp) {

  if (!filename_tmp) return 0;

  delete[] filename;
  filename = new char[strlen(filename_tmp) + 1];
  strcpy(filename, filename_tmp);

  ExtractSmiles();

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ExtractSmiles(int begin, int final) {

  if (!filename) return 0;

  ifstream  filestr;

  filestr.open (filename, ios::in);
  if (!filestr.is_open()) return 0;

  char    *lineInput = new char[1000];
  int      numberLine = 0, amount = final - begin + 1;

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) numberLine++;
  }

  filestr.close();
  filestr.open (filename, ios::in);
  if (!filestr.is_open()) return 0;

  numberSmiles = amount;
  if (allSmiles) delete[] allSmiles;
  allSmiles = new smileStruct[numberSmiles];
  numberLine = 0;

  long counter = 0;

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if ((numberLine++ >= begin) && (counter < amount))
      if (strlen(lineInput)) 
        allSmiles[counter++].InputLine(lineInput);
  }
  filestr.close();

  delete[] lineInput;

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ExtractSmiles(char *filename_tmp, int begin, int amount) {

  if (!filename_tmp) return 0;

  delete[] filename;
  filename = new char[strlen(filename_tmp) + 1];
  strcpy(filename, filename_tmp);

  ExtractSmiles(begin, amount);

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainLingos(void) {

  if (!numberSmiles) ExtractSmiles();
  for (int i = 0; i < numberSmiles; i++) allSmiles[i].ObtainLingos();
  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainLingos(char *filename_tmp) {

  if (!filename_tmp) return -1;
  ExtractSmiles(filename_tmp);
  for (int i = 0; i < numberSmiles; i++) allSmiles[i].ObtainLingos();
  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainLingos(const smileStruct *allSmiles_tmp, int numberSmiles_tmp) {

  if (!allSmiles_tmp || !numberSmiles_tmp) return -1;
  AllSmiles(allSmiles_tmp, numberSmiles_tmp);
  for (int i = 0; i < numberSmiles; i++) allSmiles[i].ObtainLingos();
  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainSimilarityMatrix(void) {

  if (!allSmiles) return -1;
  if (!numberSmiles) ObtainLingos();

  lingoSimilarity = new double*[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    lingoSimilarity[i] = new double;
    for (int j = 0; j < numberSmiles; j++)
      if (i != j) lingoSimilarity[i][j] = lingoSimilarity[j][i] = allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
      else 				lingoSimilarity[i][j] = 1;
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainSimilarityMatrix(char *filename_tmp) {

  ObtainLingos(filename_tmp);

  lingoSimilarity = new double*[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    lingoSimilarity[i] = new double;
    for (int j = 0; j < numberSmiles; j++)
      if (i != j) lingoSimilarity[i][j] = lingoSimilarity[j][i] = allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
      else 				lingoSimilarity[i][j] = 1;
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainSimilarityMatrix(const smileStruct *allSmiles_tmp, int numberSmiles_tmp) {

  ObtainLingos(allSmiles_tmp, numberSmiles_tmp);

  lingoSimilarity = new double*[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    lingoSimilarity[i] = new double;
    for (int j = 0; j < numberSmiles; j++)
      if (i != j) lingoSimilarity[i][j] = lingoSimilarity[j][i] = allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
      else 				lingoSimilarity[i][j] = 1;
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainAverageSimDistance(void) {

  if (!allSmiles) return -1;
  if (!numberSmiles) ObtainLingos();

  averageSimDistance = new double[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    averageSimDistance[i] = 0;
    for (int j = 0; j < numberSmiles; j++) {
      if (i != j) averageSimDistance[i] += allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
      printf("Average [%d] %f\n", j, averageSimDistance[i]);
    }
    averageSimDistance[i] /= (numberSmiles - 1);
    printf("Average [%d] %f\n", i, averageSimDistance[i]);
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainAverageSimDistance(char *filename_tmp) {

  ObtainLingos(filename_tmp);

  averageSimDistance = new double[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    averageSimDistance[i] = 0;
    for (int j = 0; j < numberSmiles; j++)
      if (i != j) averageSimDistance[i] += allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
    averageSimDistance[i] /= (numberSmiles - 1);
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::ObtainAverageSimDistance(const smileStruct *allSmiles_tmp, int numberSmiles_tmp) {

  ObtainLingos(allSmiles_tmp, numberSmiles_tmp);

  averageSimDistance = new double[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) {
    averageSimDistance[i] = 0;
    for (int j = 0; j < numberSmiles; j++)
      if (i != j) averageSimDistance[i] += allSmiles[i].ComputeLingoSimilarity(allSmiles[j]);
    averageSimDistance[i] /= (numberSmiles - 1);
  }

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::RandomFile(int iteration = 1) {

  if (!filename) return;

  fstream  filestr;

  //Read the data in input file
  filestr.open (filename, ios::in);
  if (!filestr.is_open()) return;

  char    *lineInput = new char[1000];
  int      numberLine = 0;

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) numberLine++;
  }

  numberSmiles = numberLine;
  if (allSmiles) delete[] allSmiles;
  allSmiles = new smileStruct[numberSmiles];
  numberLine = 0;

  filestr.close();
  filestr.open (filename, ios::in);

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) allSmiles[numberLine++].InputLine(lineInput);
  }
  filestr.close();
  delete[] lineInput;

  //Random process
  filestr.open (filename, ios::out);

  vector <int> randomFlag;
  
  for (int i = 0; i < numberSmiles; ++i) randomFlag.push_back(i);
  for (int i = 0; i < iteration; i++)    random_shuffle(randomFlag.begin(), randomFlag.end());
  
  for (int i = 0; i < numberSmiles; i++) {
    char *tmpLineInput = new char[strlen(allSmiles[randomFlag.at(i)].Code()) + strlen(allSmiles[randomFlag.at(i)].Id()) + 3];
    if (!i) sprintf(tmpLineInput,   "%s %s", allSmiles[randomFlag.at(i)].Code(), allSmiles[randomFlag.at(i)].Id());
    else    sprintf(tmpLineInput, "\n%s %s", allSmiles[randomFlag.at(i)].Code(), allSmiles[randomFlag.at(i)].Id());
    filestr.write(tmpLineInput, strlen(tmpLineInput));
  }

  filestr.close();

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::OrderFile(char *initialFileName, char *nameFileClusterMol, int ancestor) {

  if (!initialFileName && !nameFileClusterMol) return;

  fstream  filestr, clusterStr;

  //Read the data in input file
  filestr.open(initialFileName, fstream::in);
  if (!filestr.is_open()) return;
  char *lineInput = new char[1001];
  int   numberLine = 0;
  
  while (!filestr.eof()) { filestr.getline(lineInput, 1000); if (strlen(lineInput)) numberLine++; }

  numberSmiles = numberLine;
  if (allSmiles) delete[] allSmiles;
  allSmiles = new smileStruct[numberSmiles];
  numberLine = 0;

  filestr.close();
  filestr.open (initialFileName, fstream::in);
  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) allSmiles[numberLine++].InputLine(lineInput);
  }
  filestr.close();

  int   count = 0;
  long **listMol = new long*[numberSmiles];
  for (int i = 0; i < numberSmiles; i++) listMol[i] = new long[ancestor + 1];

  clusterStr.open(nameFileClusterMol, fstream::in);
  if (!clusterStr.is_open()) return;

  while (!clusterStr.eof()) {
    clusterStr.getline(lineInput, 1000);
    if (strlen(lineInput)) {
      for (int i = 0; i < ancestor + 1; i++)
        listMol[count][i]   = splitPosLineIdCode(lineInput, (i + 1));
      count++;
    }
    if (count > numberSmiles) break;
  }
  clusterStr.close();

  delete[] lineInput;

  //Order Process
  filestr.open (filename, fstream::out);

  orderListAncestor(listMol, numberSmiles, ancestor);

  //Order Cluster File
  clusterStr.open(nameFileClusterMol, fstream::out);
  
  for (int i = 0; i < numberSmiles; i++) {
    for (int j = 0; j < ancestor + 1; j++) {
      clusterStr << left;
      clusterStr.width(12);
      clusterStr << listMol[i][j] << " ";
    }
    clusterStr << endl;
  }

  clusterStr.close();

  for (int i = 0; i < numberSmiles; i++)
    for (int j = 0; j < numberSmiles; j++)
      if (atoi(allSmiles[j].Id()) == listMol[i][0]) {
        char *tmpLineInput = new char[strlen(allSmiles[j].Code()) + strlen(allSmiles[j].Id()) + 3];
        sprintf(tmpLineInput, "%s %s\0", allSmiles[j].Code(), allSmiles[j].Id());
        filestr << tmpLineInput << endl;
        break;
      }
  

  filestr.close();

  for (int i = 0; i < numberSmiles; i++) if (listMol[i]) delete listMol[i];
  if (listMol) delete[] listMol;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::ReduceFile(char *initialFileName, char *nameFileClusterMol) {
    
  if (!initialFileName && !nameFileClusterMol) return;

  fstream  filestr, clusterStr;

  //Read the data in input file
  filestr.open(initialFileName, fstream::in);
  if (!filestr.is_open()) return;
  char *lineInput = new char[1001];
  int   numberLine = 0;

  while (!filestr.eof()) { filestr.getline(lineInput, 1000); if (strlen(lineInput)) numberLine++; }

  numberSmiles = numberLine;
  if (allSmiles) delete[] allSmiles;
  allSmiles = new smileStruct[numberSmiles];
  numberLine = 0;

  filestr.close();
  filestr.open (initialFileName, fstream::in);
  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) allSmiles[numberLine++].InputLine(lineInput);
  }
  filestr.close();

  smileStruct  *tmpClusterMol;

  clusterStr.open(nameFileClusterMol, fstream::in);
  if (!clusterStr.is_open()) return;

  numberLine = 0;
  
  while (!clusterStr.eof()) { clusterStr.getline(lineInput, 1000); if (strlen(lineInput)) numberLine++; }

  int numberClusterSmiles = numberLine;
  tmpClusterMol = new smileStruct[numberClusterSmiles];
  numberLine = 0;

  clusterStr.close();
  clusterStr.open (nameFileClusterMol, fstream::in);
  while (!clusterStr.eof()) {
    clusterStr.getline(lineInput, 1000);
    if (strlen(lineInput)) tmpClusterMol[numberLine++].InputLine(lineInput);
  }
  clusterStr.close();

  filestr.open(initialFileName, fstream::out);

  for (int i = 0; i < numberSmiles; i++)
    for (int j = 0; j < numberLine; j++)
      if (atoi(allSmiles[i].Id()) == atoi(tmpClusterMol[j].Id())) {
        char *tmpLineInput = new char[strlen(allSmiles[i].Code()) + strlen(allSmiles[i].Id()) + 3];
        sprintf(tmpLineInput, "%s %s\0", allSmiles[i].Code(), allSmiles[i].Id());
        filestr << tmpLineInput << endl;
        break;
      }

  filestr.close();

  delete[] tmpClusterMol;
  delete[] lineInput;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::splitPosLineIdCode(char *line, int pos) {

  char *pch, *lineTmp = new char[strlen(line) + 1];
  int   count = 1;

  strcpy(lineTmp, line);

  pch = strtok(lineTmp, " ");
  if (pos == 1) return atoi(pch);

  while (pch != NULL) {
    pch = strtok(NULL, " ");
    if (++count == pos) return atoi(pch);
  }

  delete[] lineTmp;

  return -1;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int smileStore::orderListAncestor(long **&listMol, int numberSmiles, int ancestor) {

  for (int i = 0; i < ancestor + 1; i++) {

    int *initial = NULL, *final = NULL, numberCicles = 0;

    if (!i) {

      numberCicles  = 1;
      initial       = new int;
      *initial      = 0;
      final         = new int;
      *final        = numberSmiles;
      
    }
    else {
        
      long tmpValue = -1, *listMol_tmp = new long[numberSmiles];
      
      for (int j = 0; j < numberSmiles; j++) 
        listMol_tmp[j] = listMol[j][ancestor - i + 1];
      //MergeSort(listMol_tmp, numberSmiles);

      for (int j = 0; j < numberSmiles; j++) 
        if (listMol_tmp[j] != tmpValue) {
          tmpValue = listMol_tmp[j];
          numberCicles++;
        }

      initial = new int[numberCicles];
      final   = new int[numberCicles];

      numberCicles =  0;
      tmpValue  = -1;
      
      for (int j = 0; j < numberSmiles; j++) {
        if (listMol_tmp[j] != tmpValue) {
          if (numberCicles)
            final[numberCicles - 1] = j;
          initial[numberCicles++] = j;
          tmpValue = listMol_tmp[j];
        }
      }
      
      final[numberCicles - 1] = numberSmiles;
      
      delete[] listMol_tmp;

    }

    if (!initial || !final) continue;
    
    for (int z = 0; z < numberCicles; z++) {
        
      for (int j = initial[z]; j < final[z] - 1; j++)
        for (int k = j; k < final[z]; k++) {
          if (listMol[k][ancestor - i] < listMol[j][ancestor - i]) {
            long *LisMol_tmp = listMol[k];
            listMol[k]       = listMol[j];
            listMol[j]       = LisMol_tmp;
          }
        }
    }

    delete[] initial;
    delete[] final;

  }
    
}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::MixArray(long *array, int n) {

  long *array1, *array2;
  int n1, n2, i, j;

  if (n > 1) {
    if (n%2 == 0)   n1 = n2 = (int)n/2;
    else         {  n1 = (int)n/2; n2 = n1 + 1; }

    array1  = new long[n1];
    array2  = new long[n2];

    for (i = 0; i < n1; i++)      array1[i] = array[i];
    for (j = 0; j < n2; i++, j++) array2[j] = array[i];

    MixArray(array1, n1);
    MixArray(array2, n2);
    MixArrayX(array1, n1, array2, n2, array);

    delete[] array1;
    delete[] array2;

  }

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::MixArrayX(long *array1, int n1, long *array2, int n2, long *array3) {

  int x1 = 0, x2 = 0, x3 = 0;

  while (x1 < n1 && x2 < n2)
    if (array1[x1] < array2[x2])  array3[x3++] = array1[x1++];
    else                          array3[x3++] = array2[x2++];
  while (x1 < n1) array3[x3++] = array1[x1++];
  while (x2 < n2) array3[x3++] = array2[x2++];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void smileStore::MergeSort(long *array, int n) {

  MixArray(array, n);

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
